﻿using Away.IdentityServer.Core.Api;
using Away.IdentityServer.Core.Auth;
using Away.IdentityServer.Core.Repositories.DB;
using Away.IdentityServer.Core.Repositories.DB.UserEntities;
using Away.IdentityServer.Core.Utils;
using Microsoft.AspNetCore.Identity;
using Microsoft.OpenApi.Models;
using System.Security.Cryptography.X509Certificates;
using System.Text.Json;
using System.Text.Json.Serialization;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAwayDI();
builder.AddSwagger();
builder.Services.AddAntiforgery();
builder.Services.AddHealthChecks();
builder.Services.AddCors(o => o.AddDefaultPolicy(c => c.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));

builder.AddIds4().AddAuth();

builder.Services
   .AddControllersWithViews()
   .AddJsonOptions(options =>
   {
       options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
       options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
       options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
   });

builder.Services.ConfigureHttpJsonOptions(options =>
{
    options.SerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
    options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    options.SerializerOptions.Converters.Add(new DateTimeConverter());
});

var app = builder.Build();

app.UseSwagger();
app.UseSwaggerUI();
app.MapSwagger();
app.UseCors();
app.MapHealthChecks("healthcheck");

app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapDefaultControllerRoute();

app.MapUserApi()
    .MapApiResourceApi()
    .MapIdResourceApi()
    .MapApiScopeApi()
    .MapClientApi();

app.UseIdentityServer();
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.Run();


public static class WebApplicationBuildExtensions
{
    public static WebApplicationBuilder AddIds4(this WebApplicationBuilder builder)
    {
        AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
        var conn = builder.Configuration.GetConnectionString("pgsql");
        void dbSetting(DbContextOptionsBuilder b)
        {
            b.UseNpgsql(conn, sql => sql.MigrationsAssembly("Away.IdentityServer.Host"));
        }

        X509Certificate2 Cert()
        {
            var filename = Path.Combine(Directory.GetCurrentDirectory(), "ids4.pfx");
            return new X509Certificate2(filename, "admin@123.");
        }

        builder.Services.AddDbContext<UserDbContext>(dbSetting);
        builder.Services.AddIdentityCore<UserEntity>()
            .AddEntityFrameworkStores<UserDbContext>()
            .AddApiEndpoints();

        builder.Services
            .AddIdentityServer(o =>
            {
                o.Authentication.CookieAuthenticationScheme = "Cookies";
            })
            .AddConfigurationStore(o =>
            {
                o.ConfigureDbContext = b => dbSetting(b);
            })
            .AddOperationalStore(o =>
            {
                o.ConfigureDbContext = b => dbSetting(b);
            })
            .AddSigningCredential(Cert())
           .AddTestUsers(Config.Users)
           ;
        return builder;
    }

    public static WebApplicationBuilder AddAuth(this WebApplicationBuilder builder)
    {
        var ids4Settings = builder.Configuration.GetSection("Ids4Settings").Get<Ids4ApiSettings>();
        builder.Services
            .AddAuthentication()
            .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, o =>
            {
                o.RequireHttpsMetadata = false;
                o.Authority = ids4Settings.Url;
                o.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidIssuer = ids4Settings.Url,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(ids4Settings.ApiSecret)),
                    ValidateIssuerSigningKey = true,
                    ValidateAudience = false,
                    ClockSkew = TimeSpan.Zero
                };
            })
            .AddCookie("Cookies");
        return builder;
    }

    public static WebApplicationBuilder AddSwagger(this WebApplicationBuilder builder)
    {
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen(o =>
        {
            o.AddSecurityDefinition("JWT", new OpenApiSecurityScheme
            {
                Type = SecuritySchemeType.Http,
                In = ParameterLocation.Header,
                Name = "Authorization",
                Scheme = "Bearer",
                Description = "在http header 添加参数：Authorization:Bearer <签名>"
            });

            // 载入xml 接口文档
            var files = Directory.EnumerateFiles(AppDomain.CurrentDomain.BaseDirectory);
            var xmlPath = files.Where(o => o.EndsWith(".xml"));

            if (xmlPath.Any())
            {
                foreach (var path in xmlPath)
                {
                    o.IncludeXmlComments(path);
                }
            }
        });
        return builder;
    }
}